﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Threading;

using DragDraw.UserService;

namespace DragDraw.Util
{
    /// <summary>
    /// 管理服务的访问，同步多个服务访问
    /// </summary>
    public class ServiceManager
    {
        #region singleton
        private static ServiceManager m_instance = new ServiceManager();
        public static ServiceManager Instance { get { return m_instance; } }
        #endregion

        private object m_lock = new object();
        private WebClient m_fileClient;

        // map widgetID to listener
        private Dictionary<int, Dictionary<string, IDuplexSessionServiceListener>> m_duplexListeners
            = new Dictionary<int,Dictionary<string,IDuplexSessionServiceListener>>();

        private ServiceManager()
        {
            UserServiceBasicClient.Instance.Client.LoginCompleted += OnLoginCompleted;
            UserServiceBasicClient.Instance.Client.RegisterCompleted += OnRegisterCompleted;
            UserServiceBasicClient.Instance.Client.GetUserInfoCompleted += OnGetUserInfoCompleted;
            UserServiceBasicClient.Instance.Client.SetUserInfoCompleted += OnSetUserInfoCompleted;
            UserServiceBasicClient.Instance.Client.SetPasswordCompleted += OnSetPasswordCompleted;
            UserServiceBasicClient.Instance.Client.GetSpaceInfoCompleted += OnGetSpaceInfoCompleted;
            UserServiceBasicClient.Instance.Client.SetSpaceInfoCompleted += OnSetSpaceInfoCompleted;
            UserServiceBasicClient.Instance.Client.GetWidgetListCompleted += OnGetWidgetListCompleted;
            UserServiceBasicClient.Instance.Client.AddWidgetInfoCompleted += OnAddWidgetInfoCompleted;
            UserServiceBasicClient.Instance.Client.DeleteWidgetInfoCompleted += OnDelWidgetInfoCompleted;
            UserServiceBasicClient.Instance.Client.UpdateWidgetInfoCompleted += OnUpdateWidgetInfoCompleted;
            UserServiceBasicClient.Instance.Client.GetMessageListCompleted += OnGetMessageListCompleted;
            UserServiceBasicClient.Instance.Client.SendMessageCompleted += OnSendMessageCompleted;
            UserServiceBasicClient.Instance.Client.GetSessionCompleted += OnGetSessionCompleted;
            UserServiceBasicClient.Instance.Client.SetSessionCompleted += OnSetSessionCompleted;
            UserServiceBasicClient.Instance.Client.GetFriendListCompleted += OnGetFriendListCompleted;
            UserServiceBasicClient.Instance.Client.AddFriendCompleted += OnAddFriendCompleted;
            UserServiceBasicClient.Instance.Client.DelFriendCompleted += OnDelFriendCompleted;
            UserServiceBasicClient.Instance.Client.GetSystemSettingCompleted += OnGetSystemSettingCompleted;
            UserServiceBasicClient.Instance.Client.GetLastErrorCompleted += OnGetLastErrorCompleted;
            //UserServiceBasicClient.Instance.Client.UploadFileCompleted += OnUploadFileCompleted;

            UserServiceDuplexClient.Instance.OnReceive += OnDuplexReceiveCompleted;
            
            //wait for the two service connection
            if (!UserServiceBasicClient.Instance.Ready && !UserServiceDuplexClient.Instance.Ready) 
                Thread.Sleep(1000);

            m_fileClient = new WebClient();
            m_fileClient.OpenReadCompleted += OnLoadFileCompleted;
            m_fileClient.OpenWriteCompleted += OnSaveFileCompleted;
        }

        #region internal methods

        /// <summary>
        /// 登录方法
        /// 自动load userinfo, load friendlist, load space
        /// </summary>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        internal void Login(string username, string password, ISystemServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.LoginAsync(username, password, listener);
        }

        /// <summary>
        /// 注册方法
        /// </summary>
        /// <param name="userInfo"></param>
        /// <param name="password"></param>
        internal void Register(UserInfo userInfo, string password, ISystemServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.RegisterAsync(userInfo, password, listener);
        }

        /// <summary>
        /// 获取指定用户信息
        /// </summary>
        /// <param name="userID">用户ID</param>
        internal void GetUserInfo(string userID, IUserServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.GetUserInfoAsync(userID, listener);
        }

        /// <summary>
        /// 保存当前用户信息
        /// </summary>
        /// <param name="userInfo">用户信息</param>
        /// <param name="password">密码</param>
        internal void SetUserInfo(UserInfo userInfo, IUserServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.SetUserInfoAsync(userInfo, listener);
        }

        internal void SetPassword(string userID, string password, IUserServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.SetPasswordAsync(userID, password, listener);
        }

        /// <summary>
        /// 获取指定用户的空间
        /// </summary>
        /// <param name="userID">用户ID</param>
        internal void GetSpaceInfo(string userID, ISpaceServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.GetSpaceInfoAsync(userID, listener);
        }

        /// <summary>
        /// 保存当前用户的空间信息
        /// </summary>
        /// <param name="spaceInfo">空间信息</param>
        internal void SetSpaceInfo(SpaceInfo spaceInfo, ISpaceServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.SetSpaceInfoAsync(spaceInfo, listener);
        }

        internal void AddWidgetInfo(WidgetInfo widgetInfo, IWidgetServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.AddWidgetInfoAsync(widgetInfo, listener);
        }

        internal void UpdateWidgetInfo(WidgetInfo widgetInfo, IWidgetServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.UpdateWidgetInfoAsync(widgetInfo, listener);
        }

        internal void GetWidgetList(int spaceID, IWidgetServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.GetWidgetListAsync(spaceID, listener);
        }

        internal void DelWidgetInfo(int spaceID, int widgetID, IWidgetServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.DeleteWidgetInfoAsync(spaceID, widgetID, listener);
        }

        internal void GetMessageList(string userID, IMessageServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.GetMessageListAsync(userID, listener);
        }

        internal void SendMessage(string srcID, string destID, string tag, string body, IMessageServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.SendMessageAsync(srcID, destID, tag, body, listener);
        }

        internal void GetSession(int widgetID, string sessionName, ISessionServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.GetSessionAsync(widgetID, sessionName, listener);
        }

        internal void SetSession(int widgetID, string sessionName, string value, ISessionServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.SetSessionAsync(widgetID, sessionName,
                value, listener);
        }

        internal void AddFriend(string userID, string friendID, IFriendServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.AddFriendAsync(
                userID, friendID, listener);
        }

        internal void DelFriend(string userID, string friendID, IFriendServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.DelFriendAsync(
                userID, friendID, listener);
        }

        internal void GetFriendList(string userID, IFriendServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.GetFriendListAsync(userID, listener);
        }

        internal void GetSystemSetting(ISystemServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.GetSystemSettingAsync(listener);
        }

        internal void GetLastError(IErrorServiceListener listener)
        {
            UserServiceBasicClient.Instance.Client.GetLastErrorAsync(listener);
        }

        internal void LoadFile(string url, IFileServiceListener listener)
        {
            m_fileClient.OpenReadAsync(new Uri(url), listener);
        }

        internal void SaveFile(string url, IFileServiceListener listener)
        {
            m_fileClient.OpenWriteAsync(new Uri(url), null, listener);
        }

        internal void JoinSession(string userID, int widgetID, string sessionName, IDuplexSessionServiceListener listener)
        {
            Dictionary<string, IDuplexSessionServiceListener> d;
            if (m_duplexListeners.ContainsKey(widgetID) == false)
            {
                d = new Dictionary<string, IDuplexSessionServiceListener>();
                m_duplexListeners.Add(widgetID,
                    d);
            }
            else
            {
                d = m_duplexListeners[widgetID];
            }
            if (d.ContainsKey(sessionName))
            {
                ErrorManager.Instance.ShowDebugMessage("duplex listener already existed!");
            }
            else
            {
                d.Add(sessionName, listener);
            }
            
            UserServiceDuplexClient.Instance.SendJoinSession(userID, widgetID, sessionName);
        }

        internal void UpdateSession(SessionData session, IDuplexSessionServiceListener listener)
        {
            if (m_duplexListeners.ContainsKey(session.WidgetID) == false ||
                m_duplexListeners[session.WidgetID].ContainsKey(session.SessionName) == false)
                ErrorManager.Instance.ShowDebugMessage("duplex listener not found");

            UserServiceDuplexClient.Instance.SendUpdateSession(session);
        }

        #endregion

        #region service event handler
        void OnLoginCompleted(object sender, LoginCompletedEventArgs e)
        {
            if (e.Error != null)            
                ErrorManager.Instance.ShowException(e.Error);
            if(e.UserState != null)
                ((ISystemServiceListener)e.UserState).OnLogin(e);
        }

        void OnRegisterCompleted(object sender, RegisterCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((ISystemServiceListener)e.UserState).OnRegister(e);
        }

        void OnGetUserInfoCompleted(object sender, GetUserInfoCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IUserServiceListener)e.UserState).OnGetUserInfo(e);
        }

        void OnSetUserInfoCompleted(object sender, SetUserInfoCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IUserServiceListener)e.UserState).OnSetUserInfo(e);
        }

        void OnSetPasswordCompleted(object sender, SetPasswordCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IUserServiceListener)e.UserState).OnSetPassword(e);
        }

        void OnGetSpaceInfoCompleted(object sender, GetSpaceInfoCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((ISpaceServiceListener)e.UserState).OnGetSpaceInfo(e);
        }

        void OnSetSpaceInfoCompleted(object sender, SetSpaceInfoCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((ISpaceServiceListener)e.UserState).OnSetSpaceInfo(e);
        }

        void OnGetWidgetListCompleted(object sender, GetWidgetListCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IWidgetServiceListener)e.UserState).OnGetWidgetList(e);
        }

        void OnAddWidgetInfoCompleted(object sender, AddWidgetInfoCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IWidgetServiceListener)e.UserState).OnAddWidgetInfo(e);
        }

        void OnDelWidgetInfoCompleted(object sender, DeleteWidgetInfoCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IWidgetServiceListener)e.UserState).OnDeleteWidgetInfo(e);
        }

        void OnUpdateWidgetInfoCompleted(object sender, UpdateWidgetInfoCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IWidgetServiceListener)e.UserState).OnUpdateWidgetInfo(e);
        }

        void OnGetMessageListCompleted(object sender, GetMessageListCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IMessageServiceListener)e.UserState).OnGetMessageList(e);
        }

        void OnSendMessageCompleted(object sender, SendMessageCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IMessageServiceListener)e.UserState).OnSendMessage(e);
        }

        void OnGetSessionCompleted(object sender, GetSessionCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((ISessionServiceListener)e.UserState).OnGetSession(e);
        }

        void OnSetSessionCompleted(object sender, SetSessionCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((ISessionServiceListener)e.UserState).OnSetSession(e);
        }

        void OnGetFriendListCompleted(object sender, GetFriendListCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IFriendServiceListener)e.UserState).OnGetFriendList(e);
        }

        void OnAddFriendCompleted(object sender, AddFriendCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IFriendServiceListener)e.UserState).OnAddFriend(e);
        }

        void OnDelFriendCompleted(object sender, DelFriendCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IFriendServiceListener)e.UserState).OnDelFriend(e);
        }

        void OnGetSystemSettingCompleted(object sender, GetSystemSettingCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((ISystemServiceListener)e.UserState).OnGetSystemSetting(e);
        }

        void OnSaveFileCompleted(object sender, OpenWriteCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IFileServiceListener)e.UserState).OnSaveFile(e);
        }

        void OnLoadFileCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IFileServiceListener)e.UserState).OnLoadFile(e);
        }

        void OnDuplexReceiveCompleted(object sender, OnUpdateSessionEventArgs e)
        {
            // find proper listeners
            if (m_duplexListeners.ContainsKey(e.Result.WidgetID))
            {
                Dictionary<string, IDuplexSessionServiceListener> d
                    = m_duplexListeners[e.Result.WidgetID];
                if (d.ContainsKey(e.Result.SessionName))
                {
                    d[e.Result.SessionName].OnUpdateSession(e);
                    return;
                }
            }
            ErrorManager.Instance.ShowDebugMessage("DuplexListener not found");
        }

        void OnGetLastErrorCompleted(object sender, GetLastErrorCompletedEventArgs e)
        {
            if (e.Error != null)
                ErrorManager.Instance.ShowException(e.Error);
            if (e.UserState != null)
                ((IErrorServiceListener)e.UserState).OnGetLastError(e);
        }
        #endregion
    }

    #region listeners
    public interface ISystemServiceListener
    {
        void OnLogin(LoginCompletedEventArgs e);
        void OnRegister(RegisterCompletedEventArgs e);
        void OnGetSystemSetting(GetSystemSettingCompletedEventArgs e);
    }

    public interface IErrorServiceListener
    {
        void OnGetLastError(GetLastErrorCompletedEventArgs e);
    }

    public interface IUserServiceListener
    {
        void OnGetUserInfo(GetUserInfoCompletedEventArgs e);
        void OnSetUserInfo(SetUserInfoCompletedEventArgs e);
        void OnSetPassword(SetPasswordCompletedEventArgs e);
    }

    public interface ISpaceServiceListener
    {
        void OnGetSpaceInfo(GetSpaceInfoCompletedEventArgs e);
        void OnSetSpaceInfo(SetSpaceInfoCompletedEventArgs e);
    }

    public interface IWidgetServiceListener
    {
        void OnGetWidgetList(GetWidgetListCompletedEventArgs e);
        void OnAddWidgetInfo(AddWidgetInfoCompletedEventArgs e);
        void OnDeleteWidgetInfo(DeleteWidgetInfoCompletedEventArgs e);
        void OnUpdateWidgetInfo(UpdateWidgetInfoCompletedEventArgs e);
    }

    public interface IFileServiceListener
    {
        void OnLoadFile(OpenReadCompletedEventArgs e);
        void OnSaveFile(OpenWriteCompletedEventArgs e);
    }

    public interface ISessionServiceListener
    {
        void OnGetSession(GetSessionCompletedEventArgs e);
        void OnSetSession(SetSessionCompletedEventArgs e);
    }

    public interface IFriendServiceListener
    {
        void OnGetFriendList(GetFriendListCompletedEventArgs e);
        void OnAddFriend(AddFriendCompletedEventArgs e);
        void OnDelFriend(DelFriendCompletedEventArgs e);
    }

    public interface IMessageServiceListener
    {
        void OnSendMessage(SendMessageCompletedEventArgs e);
        void OnGetMessageList(GetMessageListCompletedEventArgs e);
    }

    public interface IDuplexSessionServiceListener
    {
        void OnUpdateSession(OnUpdateSessionEventArgs e);
    }
    #endregion
}
